<template>
  <div class="universal-table">
    <!-- 头部区域 -->
    <div class="header">
      <div class="header-left">
        <slot name="header-left">
          <h3 class="title">{{ title }}</h3>
        </slot>
      </div>

      <div class="header-right">
        <!-- 简单搜索 -->
        <!-- v-if 判断是否显示该组件 -->
        <div v-if="showSimpleSearch"
             class="simple-search">
          <!-- 
              v-model 绑定searchKey,定义为 ''
              :placeholder prop simpleSearchPlaceholder  默认为"请输入搜索关键词"
              clearable   不用管（在输入框右侧显示「×」图标）
              @keyup.enter.native  用于监听回车键  调用

              都是调用handleSearch方法（解析在下面）
           -->
          <el-input v-model="searchKey"
                    :placeholder="simpleSearchPlaceholder"
                    clearable
                    @keyup.enter.native="handleSearch"
                    class="search-input">
            <el-button slot="append"
                       icon="el-icon-search"
                       @click="handleSearch" />
          </el-input>
        </div>

        <!-- 操作按钮组 -->
        <div class="action-buttons-group">
          <!-- 高级搜索按钮 -->
          <!-- 
              showAdvancedToggle 控制高级搜索 按钮 的显示与否  
              toggleAdvancedSearch  当点击时候是否显示高级搜索区域  通过修改showAdvanced  true/false
          -->
          <el-button v-if="showAdvancedToggle"
                     type="primary"
                     icon="el-icon-search"
                     @click="toggleAdvancedSearch">
            高级搜索
          </el-button>

          <!-- 增、删、改、查、提交、处理、删除操作按钮 -->
          <!-- 
              对前端传来的 变量tableButtons 进行过滤，即当其中的 show属性为false时，不显示
              这里的 type属性为样式，有'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text'，默认为 primary
              这里的icon为图标
              @click类似于监听前端传来的 ation属性  
                例如：当前端传来的按钮属性为 add，则当点击时候，传参到handleAction中，
                代码运行至case add中，触发add被father中的handleAdd函数回调
              lable 属性： 按钮中的内容
           -->
          <el-button v-for="(btn, index) in visibleActionButtons"
                     :key="index"
                     :type="btn.type || 'primary'"
                     :icon="btn.icon"
                     :disabled="btn.disabled"
                     @click="handleAction(btn.action)">
            {{ btn.label }}
          </el-button>
        </div>
      </div>
    </div>

    <!-- 高级搜索区域 -->
    <!-- 
        当showAdvanced为false时，不展示页面，反之展示页面
     -->
    <transition name="el-zoom-in-top">
      <div v-if="showAdvanced"
           class="advanced-search">
        <!-- 
      获取当前el-form的vm，在后面使用this.$ref.searchForm调用这个vm,
      this.$refs.searchForm?.resetFields() 表单的内置方法，执行表单重置
    -->
        <el-form :model="searchForm"
                 ref="searchForm"
                 label-width="80px"
                 class="advanced-form">
          <el-row :gutter="20">
            <!-- 
          advancedFields(由father's advanced-fields prop)对应前端的advancedFields
          span为占用的空间，修改为默认8（原为6），使两个表单项能并排显示
          label为表单控件左侧的描述性文字
          prop为数据+验证 当prop为owner，这里相当于绑定了searchForm.owner
          此处的field为advancedFields遍历的每个元素
        -->
            <template v-for="(field, index) in advancedFields">
              <el-col :key="index"
                      :span="field.span || 8"
                      :md="12"
                      :sm="24"> <!-- 小屏幕全宽 -->
                <el-form-item :label="field.label"
                              :prop="field.prop">
                  <!-- 
                将配置的类型字符串转换为真实组件：
                resolveComponentType(type) {
                  const components = {
                    input: 'el-input',
                    select: 'el-select',
                    date: 'el-date-picker',
                    checkbox: 'el-checkbox-group'
                  }
                  return components[type] || 'el-input'
                }
              -->
                  <!-- 
                v-model 双向绑定 当field.prop = username时绑定searchForm.username
                v-bind 属性透传
                添加style="width:100%"使组件填满容器
              -->
                  <component :is="resolveComponentType(field.type)"
                             v-model="searchForm[field.prop]"
                             v-bind="field.props"
                             style="width: 100%">
                    <!-- 
                  当field中有options时，遍历下方的options
                  label为显示文字
                  其中的value为关联变量
                -->
                    <template v-if="field.options">
                      <el-option v-for="opt in field.options"
                                 :key="opt.value"
                                 :label="opt.label"
                                 :value="opt.value" />
                    </template>
                  </component>
                </el-form-item>
              </el-col>
            </template>
          </el-row>
          <div class="search-actions">
            <!-- 这里的搜索触发的也是前端监听的search，
                即触发father's handleSearch
         -->
            <el-button @click="resetSearch">重置</el-button>
            <el-button type="primary"
                       @click="handleSearch">搜索</el-button>
          </div>
        </el-form>
      </div>
    </transition>

    <!-- 表格主体 -->
    <div class="table-wrapper">
      <!-- 
          :data  绑定方法返回的属性
          v-bind="tableProps"  批量绑定表格配置属性  动态改变表格外观
          @selection-change="handleSelectionChange"  当用户选择行或者取消行时触发
              同时触发father's selection-change 监听，调用fathers中的handleSelectionChange函数
          column  从前端prop传来的columns

       -->
      <el-table :data="processedData"
                v-bind="tableProps"
                @selection-change="handleSelectionChange">
        <template #empty>
          <slot name="empty">
            <div class="empty-table">暂无数据</div>
          </slot>
        </template>
        <template v-for="column in columns">
          <!-- 选择列 -->
          <!--
              对father传来的columns中的元素进行遍历 
                  当元素中的type为selection时，该列的类型为selection
                  这一列的key就是空（因为该元素没有type属性）
           -->
          <!-- 
              这里的v-bind="column" 类比于：
                <el-table-column
                  :prop="column.prop"
                  :label="column.label"
                  :width="column.width"
                  :min-width="column.minWidth"
                  :fixed="column.fixed"
                  ...其他所有属性...
                />
              只露出必要的属性即可
            -->
          <el-table-column v-if="column.type === 'selection'"
                           :key="column.prop"
                           type="selection"
                           v-bind="column" />

          <!-- 操作列 -->
          <!-- 
              当father传来的type为operation时，需要自己手动添加了
           -->
          <el-table-column v-else-if="column.type === 'operation'"
                           :key="column.prop"
                           v-bind="column">
            <template #default="scope">
              <!-- 
                  在子组件中声明一个具名插槽，并暴露row数据
               -->
              <slot name="operations"
                    :row="scope.row" />
            </template>
          </el-table-column>

          <!-- 普通列 -->
          <!-- 
              除了上述两个，其他都走这里
              
            
           -->
          <el-table-column v-else
                           :key="column.prop"
                           v-bind="column">
            <template #default="scope">
              <!-- 
                  优先查找名为 column-字段名 的插槽
                  如果找不到，使用 formatCellValue 默认格式化
               -->
              <slot :name="`column-${column.prop}`"
                    :row="scope.row">
                {{ formatCellValue(scope.row, column) }}
              </slot>
            </template>
          </el-table-column>
        </template>
      </el-table>
    </div>

    <!-- 分页 -->
    <!-- 
        showPagination为prop传来的，可以通过father传来false值取消。
        属性值都是通过father传来的
     -->
    <div v-if="showPagination"
         class="pagination">
      <el-pagination :current-page="currentPage"
                     :page-sizes="pageSizes"
                     :page-size="pageSize"
                     :total="total"
                     layout="total, sizes, prev, pager, next, jumper"
                     @size-change="handleSizeChange"
                     @current-change="handlePageChange" />
    </div>
  </div>
</template>

<script>
  export default {
    name: 'UniversalTable',
    props: {
      title: String,
      data: {
        type: Array,
        required: true,
      },
      columns: {
        type: Array,
        required: true,
      },
      showSimpleSearch: {
        type: Boolean,
        default: true,
      },
      simpleSearchPlaceholder: {
        type: String,
        default: '请输入搜索关键词',
      },
      showAdvancedToggle: Boolean,
      advancedFields: {
        type: Array,
        default: () => [],
      },
      actionButtons: {
        type: Array,
        default: () => [],
      },
      showPagination: {
        type: Boolean,
        default: true,
      },
      pageSizes: {
        type: Array,
        default: () => [10, 20, 30, 50],
      },
      currentPage: {
        type: Number,
        default: 1,
      },
      pageSize: {
        type: Number,
        default: 10,
      },
      total: {
        type: Number,
        default: 0,
      },
      tableProps: {
        type: Object,
        default: () => ({}),
      },
    },
    data () {
      return {
        searchKey: '',
        showAdvanced: false,
        searchForm: {},
        selectedRows: [],
      }
    },
    computed: {
      processedData () {
        // 此处的this.data为前端接收到的data
        // this.data.map 作用：遍历数组并返回新的数组
        return this.data.map((item, index) => ({
          // 自动赋值item各种属性例如：
          // item = {id: 1, name: 2}
          // 那么此处为
          // id: 1,
          // name: 2,

          // index为每条数据添加序号，这个序号根据分页自动计算
          ...item,
          index: (this.currentPage - 1) * this.pageSize + index + 1,
        }))
      },
      visibleActionButtons () {
        return this.actionButtons.filter((btn) => btn.show !== false)
      },
    },
    methods: {
      resolveComponentType (type) {
        const componentMap = {
          input: 'el-input',
          select: 'el-select',
          date: 'el-date-picker',
        }
        return componentMap[type] || 'el-input'
      },
      formatCellValue (row, column) {
        // 安全访问属性
        const value = row[column.prop] ?? ''; // 使用空字符串作为默认值

        // 如果有格式化函数就使用，否则返回原始值
        return column.formatter
          ? column.formatter(row)
          : value;
      },
      handleSearch () {
        const params = {
          simple: this.searchKey,
          advanced: this.searchForm,
          page: this.currentPage,
          size: this.pageSize,
        }
        // 将其中的参数传给father中的 handleSearch方法，并将params传给father回调参数
        this.$emit('search', params)
      },
      resetSearch () {
        this.searchKey = ''
        // this.$refs.searchForm?.resetFields() 表单的内置方法，执行表单重置
        this.$refs.searchForm?.resetFields()
        this.$emit('reset')
      },
      toggleAdvancedSearch () {
        this.showAdvanced = !this.showAdvanced
      },
      handleSizeChange (size) {
        this.$emit('update:pageSize', size)
        // this.$emit('page-change', { page: this.currentPage, size })
      },
      handlePageChange (page) {
        this.$emit('update:currentPage', page)
        // this.$emit('page-change', { page, size: this.pageSize })
      },
      handleSelectionChange (selection) {
        this.selectedRows = selection
        this.$emit('selection-change', selection)
      },
      handleAction (action) {
        // 只触发通用事件，携带 action 和必要数据
        this.$emit('action', {
          type: action,
          selectedRows: this.selectedRows // 将动态数据一起传递
        })
      },
      setButtonVisibility (action, visible) {
        const btn = this.actionButtons.find((b) => b.action === action)
        if (btn) btn.show = visible
      },
      setButtonDisabled (action, disabled) {
        const btn = this.actionButtons.find((b) => b.action === action)
        if (btn) btn.disabled = disabled
      },
    },
  }
// queryAll () {
//         const pageParam = {
//           pageNum: this.pageNum,
//           pageSize: this.pageSize,
//         }
//         this.$axios.post('api/card/queryAll', pageParam)
//           .then(res => {
//             if (res.data.code == 200) {
//               console.log(res.data.data);
//             }
//           })
//       },
</script>

<style scoped>
  .universal-table {
    background: #fff;
    padding: 20px;
    border-radius: 4px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  }

  .header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
  }

  .header-left .title {
    margin: 0;
    font-size: 18px;
    color: #303133;
  }

  .header-right {
    display: flex;
    align-items: center;
    gap: 15px;
  }

  .search-input {
    width: 300px;
  }
  .empty-table {
    padding: 40px 0;
    text-align: center;
    color: #909399;
  }
  .action-buttons-group {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: 15px;
  }

  /* 原有样式保持不变 */
  .advanced-search {
    margin: 15px 0;
    padding: 20px;
    background: #f5f7fa;
    border-radius: 4px;
  }

  .search-actions {
    text-align: right;
    margin-top: 15px;
  }

  .table-wrapper {
    margin: 20px 0;
  }

  .pagination {
    margin-top: 20px;
    display: flex;
    justify-content: flex-end;
  }

  @media (max-width: 768px) {
    .el-col {
      width: 100%;
      margin-bottom: 15px !important;
    }

    .el-form-item {
      margin-bottom: 15px !important;
    }
  }
</style>

